package com.zhihu.matisse.loader;

import com.zhihu.matisse.MimeType;
import com.zhihu.matisse.listener.LoaderCallback;
import com.zhihu.matisse.model.Album;
import com.zhihu.matisse.model.SelectionSpec;
import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.aafwk.ability.DataUriUtils;
import ohos.app.Context;
import ohos.data.dataability.DataAbilityPredicates;
import ohos.data.resultset.CombinedResultSet;
import ohos.data.resultset.ResultSet;
import ohos.data.resultset.TableResultSet;
import ohos.media.codec.CodecDescriptionList;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import java.util.*;

public class AlbumLoader {
    private static final String COLUMN_BUCKET_ID = "_id";
    private static final String COLUMN_BUCKET_DISPLAY_NAME = "_display_name";
    public static final String COLUMN_URI = "uri";
    public static final String COLUMN_COUNT = "count";

    private static final String[] COLUMNS = {
            AVStorage.AVBaseColumns.ID,
            COLUMN_BUCKET_ID,
            COLUMN_BUCKET_DISPLAY_NAME,
            AVStorage.AVBaseColumns.MIME_TYPE,
            COLUMN_URI,
            COLUMN_COUNT,
            AVStorage.AVBaseColumns.DATE_ADDED};

    private static final String[] PROJECTION_29 = {
            COLUMN_BUCKET_ID,
            AVStorage.AVBaseColumns.DATA,
            AVStorage.AVBaseColumns.DISPLAY_NAME,
            AVStorage.AVBaseColumns.MIME_TYPE,
            AVStorage.AVBaseColumns.DATE_ADDED
    };

    private static final String SELECTION_29 =
            AVStorage.AVBaseColumns.SIZE + ">?";
    private static final String[] SELECTION_ARGS = new String[]{"1"};

    private static final String SELECTION_FOR_SINGLE_MEDIA_TYPE_29 =
            AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " OR " + AVStorage.AVBaseColumns.MIME_TYPE + "=?"
                    + " AND " + AVStorage.AVBaseColumns.SIZE + ">0";

    private static final String SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE_29 =
            AVStorage.Images.Media.SIZE + ">0"
                    + " AND " + AVStorage.Images.Media.MIME_TYPE + "=?";

    private static String[] getSelectionArgsForSingleMediaGifType() {
        return new String[]{"image/gif"};
    }
    private static String[] getSelectionArgsForSingleMediaImageType() {
        return new String[]{"image/jpeg","image/png","image/gif","image/bmp","image/heif","image/heic","image/webp"};
    }

    // =============================================

    private static final String BUCKET_ORDER_BY = "datetaken DESC";
    private Context mContext;
    private LoaderTask loaderTask;
    private LoaderCallback<ResultSet> loaderCallback;

    public void setContext(Context mContext) {
        this.mContext = mContext;
    }

    public Context getContext() {
        return mContext;
    }

    public AlbumLoader(Context mContext){
        this.mContext = mContext;

    }

    public void setLoaderCallback(LoaderCallback<ResultSet> loaderCallback) {
        this.loaderCallback = loaderCallback;
    }

    public void load(){
        String selection;
        String[] selectionArgs;
        int isVideo = -1;
        if (SelectionSpec.getInstance().onlyShowGif()) {
            selection =  SELECTION_FOR_SINGLE_MEDIA_GIF_TYPE_29;
            selectionArgs = getSelectionArgsForSingleMediaGifType();
            isVideo = 0;
        } else if (SelectionSpec.getInstance().onlyShowImages()) {
            selection = SELECTION_FOR_SINGLE_MEDIA_TYPE_29;
            selectionArgs = getSelectionArgsForSingleMediaImageType();
            isVideo = 0;
        } else if (SelectionSpec.getInstance().onlyShowVideos()) {
            isVideo = 1;
            List<String> mimes = CodecDescriptionList.getSupportedMimes();
            StringBuilder query = new StringBuilder(126);
            selectionArgs = (String[]) mimes.toArray();
            int size = mimes.size();
            for (int i = 0; i <size; i++) {
                if (i != 0){
                    query.append(" OR ");
                }
                query.append(AVStorage.AVBaseColumns.MIME_TYPE);
                query.append("=?");
            }
            query.append(" AND ");
            query.append(AVStorage.AVBaseColumns.SIZE );
            query.append(">0");
            selection = query.toString();

        } else {
            selection = SELECTION_29;
            selectionArgs = SELECTION_ARGS;
        }
        loaderTask = new LoaderTask(selection,selectionArgs,isVideo);
        loaderTask.execute();
    }
    public void cancel(boolean interruptlf){
        if (interruptlf){
            loaderCallback = null;
        }
        loaderTask.cancel(interruptlf);
    }

    class LoaderTask extends AsyncTaskLoader<String,ResultSet> {
        private String selection;
        private String[] selectionArgs;
        private int isVideo;

        LoaderTask(String selection,String[] selectionArgs,int isVideo){
            this.selection = selection;
            this.selectionArgs = selectionArgs;
            this.isVideo = isVideo;
        }


        @Override
        protected ResultSet doInBackground(String[] strings) {
            DataAbilityHelper helper = DataAbilityHelper.creator(getContext());
            ResultSet resultSet = null;
            try {
                if (selection != null){
                    DataAbilityPredicates predicates = new DataAbilityPredicates(selection);
                    predicates.setWhereArgs(Arrays.asList(selectionArgs));
                    predicates.orderByDesc(AVStorage.AVBaseColumns.ID);
                    if (isVideo == 0){
                        resultSet = helper.query(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI,PROJECTION_29, predicates);
                    }else if (isVideo == 1){
                        resultSet = helper.query(AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI,PROJECTION_29, predicates);
                    }else {
                        resultSet = helper.query(AVStorage.Files.fetchResource("external"),PROJECTION_29, predicates);
                    }
                }else {
                    DataAbilityPredicates predicates = new DataAbilityPredicates(selection);
                    predicates.setWhereArgs(Arrays.asList(selectionArgs));
                    predicates.orderByDesc(AVStorage.AVBaseColumns.ID);
                    resultSet = helper.query(AVStorage.Files.fetchResource("external"),PROJECTION_29, predicates);
                }

                if (resultSet == null) {
                    helper.release();
                    return null;
                }
                TableResultSet allAlbum = new TableResultSet(COLUMNS);
                int totalCount = 0;
                Uri allAlbumCoverUri = null;

                // Pseudo GROUP BY
                Map<String, Long> countMap = new HashMap<>();
                if (resultSet != null) {
                    while (resultSet.goToNextRow()) {
                        String data = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DATA));
                        String mimeType = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.MIME_TYPE));
                        if (MimeType.isVideo(mimeType) || MimeType.isImage(mimeType)){
                            int last = data.lastIndexOf("/");
                            String lastString = data.substring(0,last);
                            Long count = countMap.get(lastString);
                            if (count == null) {
                                count = 1L;
                            } else {
                                count++;
                            }
                            countMap.put(lastString, count);
                        }

                    }
                }
                TableResultSet otherAlbums = new TableResultSet(COLUMNS);
                if (resultSet != null) {
                    if (resultSet.goToFirstRow()) {
                        Set<String> done = new HashSet<>();
                        do {
                            long bucketId = resultSet.getLong(resultSet.getColumnIndexForName(COLUMN_BUCKET_ID));
                            String data = resultSet.getString(
                                    resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DATA));
                            String mimeType = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.MIME_TYPE));
                            long date_add = resultSet.getLong(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DATE_ADDED));
                            if (MimeType.isVideo(mimeType) || MimeType.isImage(mimeType)){
                                if (allAlbumCoverUri == null){
                                    allAlbumCoverUri = getUri(resultSet);
                                }

                                int last = data.lastIndexOf("/");
                                String lastString = data.substring(0,last);

                                int last2 = lastString.lastIndexOf("/");
                                String lastString2 = lastString.substring(last2 + 1);

                                if (done.contains(lastString)) {
                                    continue;
                                }
                                long fileId = resultSet.getLong(
                                        resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.ID));
                                long count = countMap.get(lastString);
                                Uri uri = getUri(resultSet);
                                otherAlbums.addRow(new String[]{
                                        Long.toString(fileId),
                                        Long.toString(bucketId),
                                        lastString2,
                                        mimeType,
                                        uri.toString(),
                                        String.valueOf(count),
                                        String.valueOf(date_add)});
                                done.add(lastString);

                                totalCount += count;
                            }

                        } while (resultSet.goToNextRow());
                    }
                }

                allAlbum.addRow(new String[]{
                        Album.ALBUM_ID_ALL,
                        Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, null,
                        allAlbumCoverUri == null ? null : allAlbumCoverUri.toString(),
                        String.valueOf(totalCount),"-1"});
                
                return new CombinedResultSet(new ResultSet[]{allAlbum, otherAlbums});
            } catch (DataAbilityRemoteException e) {
                return null;
            }finally {
                helper.release();
                if (resultSet != null){
                    resultSet.close();
                }
            }
        }
        private Uri getUri(ResultSet cursor) {
            long id = cursor.getLong(cursor.getColumnIndexForName(AVStorage.AVBaseColumns.ID));
            String mimeType = cursor.getString(
                    cursor.getColumnIndexForName(AVStorage.AVBaseColumns.MIME_TYPE));
            Uri contentUri;

            if (MimeType.isImage(mimeType)) {
                contentUri = AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI;
            } else if (MimeType.isVideo(mimeType)) {
                contentUri = AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI;
            } else {
                // ?
                contentUri = AVStorage.Files.fetchResource("external");
            }

            return DataUriUtils.attachId(contentUri, id);
        }
        @Override
        protected void postResult(ResultSet albums) {
            super.postResult(albums);
            if (loaderCallback != null && albums != null){
                loaderCallback.setCallback(albums);
            }
        }
    }



}
